home *** CD-ROM | disk | FTP | other *** search
-
- /*
- File: SelectionLibrary.c
-
- Contains: graphics libraries - SelectionHandle manipulation routines
-
- Written by: Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Oliver Steele, David Van Brink, Chris Yerga
-
- Copyright: © 1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <2> 1/9/95 JD changed 'boolean' to 'Boolean'
- <1> 1/9/95 JD First checked in.
- Previous History:
-
- Date Person Action
- ---- ------ ------
-
- 911031 DGO • Created module.
- 920130 DGO • Canonicalized order for range selections.
- 940606 DGO • Minor bugfixes.
-
- */
-
-
- #include <Types.h>
- #include <Memory.h>
- #include <OSUtils.h>
- #include <GXTypes.h>
- #include <GXLayout.h>
- #include <GXGraphics.h>
- #include "SelectionLibrary.h"
-
- #define siSize sizeof(Selection)
- #define sioSize (siSize + sizeof(SelectionOffsetRange))
-
- #define MyMin(a,b) (((a) < (b)) ? (a) : (b))
- #define MyMax(a,b) (((a) > (b)) ? (a) : (b))
-
- typedef enum {
- unionAll,
- unionOne,
- firstIsLow,
- secondIsLow
- } UnionOneState;
-
- /* ---------------------------------------------------------------------------------- */
-
- /* NewEmptySelection creates a Selection of type emptySelection. */
-
- SelectionHandle NewEmptySelection()
- {
- Handle h;
- SelectionPtr sip;
- if ((h = NewHandle(siSize)) == nil) {GXPostGraphicsError(out_of_memory); return nil;}
- sip = (SelectionPtr) *h;
- sip->type = emptySelection;
- return ((SelectionHandle) h);
- } /* NewEmptySelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* NewCaretSelection creates a Selection of type simpleCaret and fills it with the
- specified offset and leadingEdge information. */
-
- SelectionHandle NewCaretSelection(SelectionOffset offset, long leadingEdge)
- {
- Handle h;
- SelectionPtr sip;
- if ((h = NewHandle(siSize)) == nil) {GXPostGraphicsError(out_of_memory); return nil;}
- sip = (SelectionPtr) *h;
- sip->type = simpleCaret;
- sip->data.caret.offset = offset;
- sip->data.caret.leadingEdge = (short) leadingEdge;
- return ((SelectionHandle) h);
- } /* NewCaretSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* NewRangeSelection creates a Selection of type simpleRange and sets it to a single
- range, using the specified data. */
-
- SelectionHandle NewRangeSelection(SelectionOffsetRange *range)
- {
- Handle h;
- SelectionOffsetRange sortedRange;
- SelectionPtr sip;
- if (range == nil) {GXPostGraphicsError(parameter_is_nil); return nil;}
- if (range->minOffset == range->maxOffset)
- return NewCaretSelection(range->minOffset, false);
- else if (range->minOffset != selectionExtremeEdge && range->maxOffset != selectionExtremeEdge && range->minOffset > range->maxOffset)
- {
- sortedRange.minOffset = range->maxOffset;
- sortedRange.maxOffset = range->minOffset;
- range = &sortedRange;
- }
- if ((h = NewHandle(sioSize)) == nil) {GXPostGraphicsError(out_of_memory); return nil;}
- sip = (SelectionPtr) *h;
- sip->type = simpleRange;
- sip->data.range.rangeCount = 1;
- sip->data.range.ranges[0] = *range;
- return ((SelectionHandle) h);
- } /* NewRangeSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* NewFullSelection creates a Selection of type simpleRange and sets it to a single
- range, with both ends set to the selectionExtremeEdge value. */
-
- SelectionHandle NewFullSelection()
- {
- SelectionOffsetRange myRange;
- myRange.minOffset = myRange.maxOffset = selectionExtremeEdge;
- return NewRangeSelection(&myRange);
- } /* NewFullSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* NewStartSelection creates a Selection of type simpleRange and sets it to a single
- range, with the start set to selectionExtremeEdge and the end set to the specified
- offset. */
-
- SelectionHandle NewStartSelection(SelectionOffset toOffset)
- {
- SelectionOffsetRange myRange;
- myRange.minOffset = selectionExtremeEdge;
- myRange.maxOffset = toOffset;
- return NewRangeSelection(&myRange);
- } /* NewStartSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* NewEndSelection creates a Selection of type simpleRange and sets it to a single
- range, with the start set to the specified offset and the end set to the
- selectionExtremeEdge value. */
-
- SelectionHandle NewEndSelection(SelectionOffset fromOffset)
- {
- SelectionOffsetRange myRange;
- myRange.minOffset = fromOffset;
- myRange.maxOffset = selectionExtremeEdge;
- return NewRangeSelection(&myRange);
- } /* NewEndSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* SetEmptySelection takes an existing Selection and removes its contents, turning it
- into a Selection of type emptySelection. */
-
- void SetEmptySelection(SelectionHandle selection)
- {
- SelectionPtr sip;
- if (selection == nil || (sip = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return;}
- sip->type = emptySelection;
- } /* SetEmptySelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* SetCaretSelection takes an existing Selection and removes its contents, turning it
- into a Selection of type simpleCaret and copying the specified data into it. */
-
- void SetCaretSelection(SelectionHandle selection, SelectionOffset offset, long leadingEdge)
- {
- SelectionPtr sip;
- if (selection == nil || (sip = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return;}
- sip->type = simpleCaret;
- sip->data.caret.offset = offset;
- sip->data.caret.leadingEdge = (short) leadingEdge;
- } /* SetCaretSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* SetRangeSelection takes an existing Selection and removes its contents, turning it
- into a Selection of type simpleRange containing a single range with the specified
- offsets. */
-
- void SetRangeSelection(SelectionHandle selection, SelectionOffsetRange *range)
- {
- SelectionOffsetRange sortedRange;
- SelectionPtr sip;
- if (selection == nil || (sip = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return;}
- if (range->minOffset == range->maxOffset)
- {
- SetCaretSelection(selection, range->minOffset, false);
- return;
- }
- if (GetHandleSize((Handle) selection) < sioSize)
- { /* need to grow handle */
- SetHandleSize((Handle) selection, sioSize);
- if (MemError())
- {GXPostGraphicsError(out_of_memory); return;}
- sip = *selection; /* might have moved... */
- } /* end need to grow handle */
- if (range->minOffset > range->maxOffset)
- {
- sortedRange.minOffset = range->maxOffset;
- sortedRange.maxOffset = range->minOffset;
- range = &sortedRange;
- }
- sip->type = simpleRange;
- sip->data.range.rangeCount = 1;
- sip->data.range.ranges[0] = *range;
- } /* SetRangeSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* SetFullSelection takes an existing Selection and removes its contents, turning it
- into a Selection of type simpleRange containing a single range with both offsets
- set to the selectionExtremeEdge value. */
-
- void SetFullSelection(SelectionHandle selection)
- {
- SelectionOffsetRange myRange;
- myRange.minOffset = myRange.maxOffset = selectionExtremeEdge;
- SetRangeSelection(selection, &myRange);
- } /* SetFullSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* SetStartSelection takes an existing Selection and removes its contents, turning it into
- a Selection of type simpleRange containing a single range with the start offset set
- to the selectionExtremeEdge value and the end offset set to the specified value. */
-
- void SetStartSelection(SelectionHandle selection, SelectionOffset toOffset)
- {
- SelectionOffsetRange myRange;
- myRange.minOffset = selectionExtremeEdge;
- myRange.maxOffset = toOffset;
- SetRangeSelection(selection, &myRange);
- } /* SetStartSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* SetEndSelection takes an existing Selection and removes its contents, turning it into
- a Selection of type simpleRange containing a single range with the start offset set
- to the specified value and the end offset set to the selectionExtremeEdge value. */
-
- void SetEndSelection(SelectionHandle selection, SelectionOffset fromOffset)
- {
- SelectionOffsetRange myRange;
- myRange.minOffset = fromOffset;
- myRange.maxOffset = selectionExtremeEdge;
- SetRangeSelection(selection, &myRange);
- } /* SetEndSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* DisposeSelection disposes of the storage associated with a Selection. */
-
- void DisposeSelection(SelectionHandle selection)
- {
- if (selection == nil) {GXPostGraphicsError(parameter_is_nil); return;}
- else DisposeHandle((Handle) selection);
- } /* DisposeSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* GetSelectionType allows procedural access to the type of a Selection. */
-
- SelectionType GetSelectionType(SelectionHandle selection)
- {
- SelectionPtr sip;
- if (selection == nil || (sip = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return emptySelection;}
- else return sip->type;
- } /* GetSelectionType */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* GetCaretSelection allows procedural access to the character offset and leadingEdge
- value associated with a Selection of type simpleCaret. */
-
- SelectionOffset GetCaretSelection(SelectionHandle selection, Boolean *leadingEdge)
- {
- SelectionPtr sip;
- if (selection == nil || (sip = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return 0;}
- if (sip->type != simpleCaret)
- {
- #ifdef debugging
- GXPostGraphicsError(parameter_out_of_range);
- #endif
- return 0;
- }
- /* It is not an error for leadingEdge to be nil; in this case, we assume the client
- wasn't interested in the state of the leadingEdge flag. */
- if (leadingEdge) *leadingEdge = (Boolean) sip->data.caret.leadingEdge;
- return sip->data.caret.offset;
- } /* GetCaretSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* GetRangeSelection allows procedural access to the SelectionOffsetRange value(s)
- associated with a Selection of type simpleRange or discontiguousRange. It returns
- the total byte size needed for the resulting SelectionRanges structure; it returns
- this size even if the given selectionRanges argument is nil. */
-
- long GetRangeSelection(SelectionHandle selection, SelectionRanges *selectionRanges)
- {
- long totalSize;
- SelectionPtr sip;
- SelectionOffsetRange *pDst, *pSrc;
- short i;
- if (selection == nil || (sip = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return 0;}
- if (sip->type != simpleRange && sip->type != discontiguousRange)
- {
- #ifdef debugging
- GXPostGraphicsError(parameter_out_of_range);
- #endif
- return 0;
- }
- totalSize = sizeof(SelectionRanges) + (sip->data.range.rangeCount * sizeof(SelectionOffsetRange));
- if (selectionRanges)
- { /* copy the data */
- selectionRanges->rangeCount = sip->data.range.rangeCount;
- i = (short) selectionRanges->rangeCount;
- pDst = &selectionRanges->ranges[0];
- pSrc = &sip->data.range.ranges[0];
- while (i--) *pDst++ = *pSrc++;
- } /* end copy the data */
- return totalSize;
- } /* GetRangeSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* XXX Still don't have "equalToSelection" logic in here... XXX */
-
- /* RangeInSelection returns an indication of the degree to which the specified offset
- range is contained in the specified Selection. */
-
- SelectionMatch RangeInSelection(SelectionHandle selection, SelectionOffsetRange *range)
- {
- SelectionHandle thisRange;
- SelectionMatch retVal;
- SelectionPtr sip;
-
- thisRange = NewRangeSelection(range);
- SectSelection(thisRange, selection);
- sip = *thisRange;
- switch (sip->type)
- {
- case emptySelection:
- case simpleCaret: /* "simpleCaret" hadn't better happen here... */
- retVal = notInSelection;
- break;
- case simpleRange:
- if (range->minOffset == sip->data.range.ranges[0].minOffset && range->maxOffset == sip->data.range.ranges[0].maxOffset)
- retVal = fullyInSelection;
- else retVal = partlyInSelection;
- break;
- case discontiguousRange:
- retVal = partlyInSelection; /* is this correct? */
- break;
- }
-
- DisposeSelection(thisRange);
- return retVal;
- } /* RangeInSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* IsFullSelection determines whether a Selection has the special selectionExtremeEdge
- value as both its minOffset and maxOffset values. */
-
- static Boolean IsFullSelection(SelectionHandle s)
- {
- SelectionPtr sip;
- SelectionOffsetRange *sor;
-
- if (s == nil || (sip = *s) == nil)
- {GXPostGraphicsError(parameter_is_nil); return false;}
- if (sip->type != simpleRange && sip->type != discontiguousRange)
- return false;
- sor = &sip->data.range.ranges[0];
-
- if (sor->minOffset == selectionExtremeEdge && sor->maxOffset == selectionExtremeEdge)
- return true;
- else
- return false;
-
- } /* IsFullSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- void InvertSelection(SelectionHandle dest)
- {
- Handle tempHandle;
- SelectionPtr destSIP;
- SelectionOffsetRange *newSOR, *nextSOR, *sor;
- short count, newCount;
-
- if (dest == nil || (destSIP = *dest) == nil)
- {GXPostGraphicsError(parameter_is_nil); return;}
- if (destSIP->type == simpleCaret)
- {
- #ifdef debugging
- GXPostGraphicsError(parameter_out_of_range);
- #endif
- return;
- }
-
- if (IsFullSelection(dest)) SetEmptySelection(dest);
- else if (destSIP->type == emptySelection) SetFullSelection(dest);
- else
- { /* neither empty nor full */
- tempHandle = NewHandle((destSIP->data.range.rangeCount + 1) * sizeof(SelectionOffsetRange));
- if (tempHandle == nil)
- {GXPostGraphicsError(out_of_memory); return;}
- destSIP = *dest; /* memory might have moved */
- sor = &destSIP->data.range.ranges[0];
- nextSOR = sor + 1;
- count = (short) destSIP->data.range.rangeCount;
- newSOR = (SelectionOffsetRange *) *tempHandle;
- newCount = 0;
-
- /* At some gxPoint, we may want to deal with the problem that a non open-ended
- selection that starts at zero doesn't get restored after two inversions. */
-
- /* If first is not open-ended, add [selectionExtremeEdge, first.minOffset] */
- if (sor->minOffset != selectionExtremeEdge)
- {
- newSOR->minOffset = selectionExtremeEdge;
- (newSOR++)->maxOffset = sor->minOffset;
- newCount++;
- }
- /* Start main loop */
- while (--count) /* "--count" insures n-1 iterations */
- { /* main loop */
- newSOR->minOffset = sor->maxOffset;
- (newSOR++)->maxOffset = nextSOR->minOffset;
- newCount++;
- sor = nextSOR++;
- } /* end main loop */
- /* If last is not open-ended, add [last.maxOffset, selectionExtremeEdge] */
- if (sor->maxOffset != selectionExtremeEdge)
- {
- newSOR->minOffset = sor->maxOffset;
- newSOR->maxOffset = selectionExtremeEdge;
- newCount++;
- }
- /* Now change the size of dest (if needed) and store the new SORs into it. */
- if (newCount > (short) destSIP->data.range.rangeCount)
- {
- SetHandleSize((Handle) dest, siSize + newCount * sizeof(SelectionOffsetRange));
- destSIP = *dest; /* memory might have moved */
- }
- destSIP->data.range.rangeCount = newCount;
- destSIP->type = (SelectionType) ((newCount == 1) ? simpleRange : discontiguousRange);
- sor = &destSIP->data.range.ranges[0];
- newSOR = (SelectionOffsetRange *) *tempHandle;
- while (newCount--) *sor++ = *newSOR++;
- DisposeHandle(tempHandle);
- } /* end neither empty nor full */
-
- } /* InvertSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- void ShiftSelection(SelectionHandle dest, SelectionOffset delta)
- {
- SelectionOffsetRange *sor;
- SelectionPtr destSIP;
- short count;
-
- if (dest == nil || (destSIP = *dest) == nil)
- {GXPostGraphicsError(parameter_is_nil); return;}
-
- switch (destSIP->type)
- {
- case emptySelection:
- break;
- case simpleCaret:
- destSIP->data.caret.offset += delta;
- break;
- case simpleRange:
- case discontiguousRange:
- count = (short) destSIP->data.range.rangeCount;
- sor = &destSIP->data.range.ranges[0];
- while (count--)
- {
- if (sor->minOffset != selectionExtremeEdge) sor->minOffset += delta;
- if (sor->maxOffset != selectionExtremeEdge) sor->maxOffset += delta;
- sor++;
- }
- break;
- } /* end switch */
-
- } /* ShiftSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* GrowSI is an internal work function used to grow a Selection to allow more
- space for SelectionOffsetRanges. */
-
- static void GrowSI(
- Handle h,
- short *maxAllocated,
- SelectionPtr *sip,
- SelectionOffsetRange **dest,
- SelectionOffsetRange **prevDest)
-
- {
- short oldMax = *maxAllocated;
- *maxAllocated <<= 1;
- SetHandleSize(h, siSize + (*maxAllocated) * sizeof(SelectionOffsetRange));
- if (MemError() != noErr) GXPostGraphicsError(out_of_memory);
- *sip = (SelectionPtr) *h;
- *dest = (*sip)->data.range.ranges + oldMax;
- *prevDest = *dest - 1;
- } /* GrowSI */
-
- /* ---------------------------------------------------------------------------------- */
-
- /* UnionOne takes two SelectionOffsetRanges and determines if their union is representable
- in a single resulting SelectionOffsetRange. If it is not, the dest value is not set,
- and a value is returned that indicates whether the first or second argument starts
- earlier. If it is, the dest value is set to the union, and the unionOne value is
- returned. */
-
- static UnionOneState UnionOne(
- SelectionOffsetRange *sor1,
- SelectionOffsetRange *sor2,
- SelectionOffsetRange *dest)
-
- {
- short selector;
- UnionOneState retVal;
-
- selector = (short) ((sor1->minOffset == selectionExtremeEdge) << 3);
- selector += (short) ((sor1->maxOffset == selectionExtremeEdge) << 2);
- selector += (short) ((sor2->minOffset == selectionExtremeEdge) << 1);
- selector += (sor2->maxOffset == selectionExtremeEdge);
-
- switch (selector)
- {
-
- /* Case 0 is where neither SelectionOffsetRange is open-ended */
-
- case 0:
- if (sor1->minOffset < sor2->minOffset)
- if (sor2->minOffset <= sor1->maxOffset)
- {
- dest->minOffset = sor1->minOffset;
- dest->maxOffset = MyMax(sor1->maxOffset, sor2->maxOffset);
- retVal = unionOne;
- }
- else retVal = firstIsLow;
- else
- if (sor1->minOffset <= sor2->maxOffset)
- {
- dest->minOffset = sor2->minOffset;
- dest->maxOffset = MyMax(sor1->maxOffset, sor2->maxOffset);
- retVal = unionOne;
- }
- else retVal = secondIsLow;
- break;
-
- /* Case 1 is where the second SelectionOffsetRange is open on the right. */
-
- case 1:
- if (sor2->minOffset > sor1->maxOffset) retVal = firstIsLow;
- else
- {
- dest->minOffset = MyMin(sor1->minOffset, sor2->minOffset);
- dest->maxOffset = selectionExtremeEdge;
- retVal = unionOne;
- }
- break;
-
- /* Case 2 is where the second SelectionOffsetRange is open on the left. */
-
- case 2:
- if (sor2->maxOffset < sor1->minOffset) retVal = secondIsLow;
- else
- {
- dest->minOffset = selectionExtremeEdge;
- dest->maxOffset = MyMax(sor1->maxOffset, sor2->maxOffset);
- retVal = unionOne;
- }
- break;
-
- /* Cases 3, 7, and 11 thru 15 are where one (or both) are full selections. */
-
- case 3:
- case 7:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- dest->minOffset = dest->maxOffset = selectionExtremeEdge;
- retVal = unionAll;
- break;
-
- /* Case 4 is where the first SelectionOffsetRange is open on the right. */
-
- case 4:
- if (sor1->minOffset > sor2->maxOffset) retVal = secondIsLow;
- else
- {
- dest->minOffset = MyMin(sor1->minOffset, sor2->minOffset);
- dest->maxOffset = selectionExtremeEdge;
- retVal = unionOne;
- }
- break;
-
- /* Case 5 is where both SelectionOffsetRanges are open on the right. */
-
- case 5:
- dest->minOffset = MyMin(sor1->minOffset, sor2->minOffset);
- dest->maxOffset = selectionExtremeEdge;
- retVal = unionOne;
- break;
-
- /* Case 6 is where the first SelectionOffsetRange is open on the right and the
- second SelectionOffsetRange is open on the right. */
-
- case 6:
- if (sor1->minOffset > sor2->maxOffset) retVal = secondIsLow;
- else
- {
- dest->minOffset = dest->maxOffset = selectionExtremeEdge;
- retVal = unionAll;
- }
- break;
-
- /* Case 8 is where the first SelectionOffsetRange is open on the left. */
-
- case 8:
- if (sor1->maxOffset < sor2->minOffset) retVal = firstIsLow;
- else
- {
- dest->minOffset = selectionExtremeEdge;
- dest->maxOffset = MyMax(sor1->maxOffset, sor2->maxOffset);
- retVal = unionOne;
- }
- break;
-
- /* Case 9 is where the first SelectionOffsetRange is open on the left and the
- second SelectionOffsetRange is open on the left. */
-
- case 9:
- if (sor2->minOffset > sor1->maxOffset) retVal = firstIsLow;
- else
- {
- dest->minOffset = dest->maxOffset = selectionExtremeEdge;
- retVal = unionAll;
- }
- break;
-
- /* Case 10 is where both SelectionOffsetRanges are open on the left. */
-
- case 10:
- dest->minOffset = selectionExtremeEdge;
- dest->maxOffset = MyMax(sor1->maxOffset, sor2->maxOffset);
- retVal = unionOne;
- break;
-
- } /* end switch */
-
- return retVal;
- } /* UnionOne */
-
- /* ---------------------------------------------------------------------------------- */
-
- void UnionSelection(SelectionHandle dest, SelectionHandle source)
- {
- Handle tempHandle;
- long destCount, sor1Count, sor2Count;
- SelectionOffsetRange *destSOR, *prevDestSOR, *sor1, *sor2, workSORSpace, workSORSpace2;
- SelectionPtr destSIP, newSIP, sourceSIP;
- short maxAllocated = 10;
- Size newSize, sourceSize;
-
- /* Allocate the memory first, since we want it to be the last thing that moves mem. */
-
- newSize = siSize + maxAllocated * sizeof(SelectionOffsetRange);
- tempHandle = NewHandle(newSize);
- if (tempHandle == nil)
- {GXPostGraphicsError(out_of_memory); return;}
- destCount = 0;
- newSIP = (SelectionPtr) *tempHandle;
-
- /* Validate inputs. */
-
- if (dest == nil || (destSIP = *dest) == nil)
- {GXPostGraphicsError(parameter_is_nil); DisposeHandle(tempHandle); return;}
- if (source == nil || (sourceSIP = *source) == nil)
- {GXPostGraphicsError(parameter_is_nil); DisposeHandle(tempHandle); return;}
- if (destSIP->type == simpleCaret || sourceSIP->type == simpleCaret)
- {
- #ifdef debugging
- GXPostGraphicsError(parameter_out_of_range);
- #endif
- DisposeHandle(tempHandle);
- return;
- }
-
- /* If both the Selections are empty, just return. */
-
- if ((destSIP->type == emptySelection) && (sourceSIP->type == emptySelection))
- {DisposeHandle(tempHandle); return;}
-
- /* Handle cases where one (but not both) selection is empty. If dest is empty, this
- means just copy source to dest. If source is empty, just return. */
-
- if ((destSIP->type == emptySelection) && (sourceSIP->type != emptySelection))
- { /* copy source to dest */
- sourceSize = GetHandleSize((Handle) source);
- SetHandleSize((Handle) dest, sourceSize);
- if (MemError() != noErr) GXPostGraphicsError(out_of_memory);
- else BlockMove(*((Handle) source), *((Handle) dest), sourceSize); /* mem might have moved! */
- DisposeHandle(tempHandle);
- return;
- } /* end copy source to dest */
- else if ((destSIP->type != emptySelection) && (sourceSIP->type == emptySelection))
- {DisposeHandle(tempHandle); return;}
-
- /* At this gxPoint both selections are range selections. We can therefore begin to walk
- down the two selections in parallel, creating the new selection from the combo.
- We "seed" the process by creating the first new entry before entering the loop;
- this lets us get some of the testing code out of the loop proper. */
-
- prevDestSOR = destSOR = &newSIP->data.range.ranges[0];
- sor1 = &destSIP->data.range.ranges[0];
- sor2 = &sourceSIP->data.range.ranges[0];
- sor1Count = destSIP->data.range.rangeCount;
- sor2Count = sourceSIP->data.range.rangeCount;
- destCount = 1;
-
- HLock((Handle) dest);
- HLock((Handle) source);
-
- switch (UnionOne(sor1, sor2, &workSORSpace))
- {
- case unionAll:
- *destSOR = workSORSpace;
- sor1Count = sor2Count = 0; /* forces following loop to be skipped */
- break;
- case unionOne:
- *destSOR++ = workSORSpace;
- sor1Count--; sor1++;
- sor2Count--; sor2++;
- break;
- case firstIsLow:
- *destSOR++ = *sor1++;
- sor1Count--;
- break;
- case secondIsLow:
- *destSOR++ = *sor2++;
- sor2Count--;
- break;
- } /* end switch */
-
- while ((sor1Count > 0) || (sor2Count > 0))
- { /* main merge loop */
- if ((sor1Count > 0) && (sor2Count > 0))
- { /* still have both */
- switch (UnionOne(sor1, sor2, &workSORSpace))
- {
- case unionAll:
- newSIP->data.range.ranges[0] = workSORSpace;
- destCount = 1;
- sor1Count = sor2Count = 0;
- break;
- case unionOne:
- switch (UnionOne(prevDestSOR, &workSORSpace, &workSORSpace2))
- {
- case unionAll:
- newSIP->data.range.ranges[0] = workSORSpace2;
- destCount = 1;
- sor1Count = sor2Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- case unionOne:
- *prevDestSOR = workSORSpace2;
- break;
- case firstIsLow:
- if (destCount == maxAllocated)
- GrowSI(tempHandle, &maxAllocated, &newSIP, &destSOR, &prevDestSOR);
- *destSOR = workSORSpace;
- destCount++;
- prevDestSOR = destSOR++;
- break;
- case secondIsLow:
- GXPostGraphicsError(internal_layout_error);
- sor1Count = sor2Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- } /* end switch */
- sor1++; sor2++;
- sor1Count--; sor2Count--;
- break;
- case firstIsLow:
- switch (UnionOne(prevDestSOR, sor1, &workSORSpace))
- {
- case unionAll:
- newSIP->data.range.ranges[0] = workSORSpace;
- destCount = 1;
- sor1Count = 1; /* dec'd to 0 below, forces loop exit */
- sor2Count = 0;
- break;
- case unionOne:
- *prevDestSOR = workSORSpace;
- break;
- case firstIsLow:
- if (destCount == maxAllocated)
- GrowSI(tempHandle, &maxAllocated, &newSIP, &destSOR, &prevDestSOR);
- *destSOR = *sor1;
- destCount++;
- prevDestSOR = destSOR++;
- break;
- case secondIsLow:
- GXPostGraphicsError(internal_layout_error);
- sor1Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- } /* end switch */
- sor1++;
- sor1Count--;
- break;
- case secondIsLow:
- switch (UnionOne(prevDestSOR, sor2, &workSORSpace))
- {
- case unionAll:
- newSIP->data.range.ranges[0] = workSORSpace;
- destCount = 1;
- sor1Count = 0;
- sor2Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- case unionOne:
- *prevDestSOR = workSORSpace;
- break;
- case firstIsLow:
- if (destCount == maxAllocated)
- GrowSI(tempHandle, &maxAllocated, &newSIP, &destSOR, &prevDestSOR);
- *destSOR = *sor2;
- destCount++;
- prevDestSOR = destSOR++;
- break;
- case secondIsLow:
- GXPostGraphicsError(internal_layout_error);
- sor2Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- } /* end switch */
- sor2++;
- sor2Count--;
- break;
- } /* end switch */
- } /* end still have both */
- else if (sor1Count > 0)
- { /* still have first */
- switch (UnionOne(prevDestSOR, sor1, &workSORSpace))
- {
- case unionAll:
- newSIP->data.range.ranges[0] = workSORSpace;
- destCount = 1;
- sor1Count = 1; /* dec'd to 0 below, forces loop exit */
- sor2Count = 0;
- break;
- case unionOne:
- *prevDestSOR = workSORSpace;
- break;
- case firstIsLow:
- if (destCount == maxAllocated)
- GrowSI(tempHandle, &maxAllocated, &newSIP, &destSOR, &prevDestSOR);
- *destSOR = *sor1;
- destCount++;
- prevDestSOR = destSOR++;
- break;
- case secondIsLow:
- GXPostGraphicsError(internal_layout_error);
- sor1Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- } /* end switch */
- sor1++;
- sor1Count--;
- } /* end still have first */
- else
- { /* still have second */
- switch (UnionOne(prevDestSOR, sor2, &workSORSpace))
- {
- case unionAll:
- newSIP->data.range.ranges[0] = workSORSpace;
- destCount = 1;
- sor1Count = 0;
- sor2Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- case unionOne:
- *prevDestSOR = workSORSpace;
- break;
- case firstIsLow:
- if (destCount == maxAllocated)
- GrowSI(tempHandle, &maxAllocated, &newSIP, &destSOR, &prevDestSOR);
- *destSOR = *sor2;
- destCount++;
- prevDestSOR = destSOR++;
- break;
- case secondIsLow:
- GXPostGraphicsError(internal_layout_error);
- sor2Count = 1; /* dec'd to 0 below, forces loop exit */
- break;
- } /* end switch */
- sor2++;
- sor2Count--;
- } /* end still have second */
- } /* end main merge loop */
-
- HUnlock((Handle) dest);
- HUnlock((Handle) source);
-
- newSize = siSize + destCount * sizeof(SelectionOffsetRange);
- SetHandleSize((Handle) dest, newSize);
- if (MemError() != noErr) GXPostGraphicsError(out_of_memory);
- destSIP = *dest;
-
- destSIP->type = (SelectionType) ((destCount == 1) ? simpleRange : discontiguousRange);
- destSIP->data.range.rangeCount = destCount;
- sor1 = &newSIP->data.range.ranges[0];
- destSOR = &destSIP->data.range.ranges[0];
- while (destCount-- > 0) *destSOR++ = *sor1++;
-
- DisposeHandle(tempHandle);
-
- } /* UnionSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- void SectSelection(SelectionHandle dest, SelectionHandle source)
- {
- SelectionHandle sourceCopy = source;
- if (HandToHand((Handle *) &sourceCopy) != noErr)
- {GXPostGraphicsError(out_of_memory); return;}
- InvertSelection(dest);
- InvertSelection(sourceCopy);
- UnionSelection(dest, sourceCopy);
- DisposeHandle((Handle) sourceCopy);
- InvertSelection(dest);
- } /* SectSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- void XorSelection(SelectionHandle dest, SelectionHandle source)
- {
- SelectionHandle sourceCopy = source;
- if (HandToHand((Handle *) &sourceCopy) != noErr)
- {GXPostGraphicsError(out_of_memory); return;}
- SectSelection(sourceCopy, dest);
- UnionSelection(dest, source);
- DiffSelection(dest, sourceCopy);
- DisposeHandle((Handle) sourceCopy);
- } /* XorSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- void DiffSelection(SelectionHandle dest, SelectionHandle source)
- {
- SelectionHandle sourceCopy = source;
- if (HandToHand((Handle *) &sourceCopy) != noErr)
- {GXPostGraphicsError(out_of_memory); return;}
- InvertSelection(sourceCopy);
- SectSelection(dest, sourceCopy);
- DisposeHandle((Handle) sourceCopy);
- } /* DiffSelection */
-
- /* ---------------------------------------------------------------------------------- */
-
- gxShape GetLayoutSelection(
- gxShape layout,
- SelectionHandle selection,
- SelectionOffset lineStart,
- gxHighlightType highlightType,
- gxCaretType caretType)
-
- {
- long maxOffset;
- SelectionOffset off1, off2;
- SelectionOffsetRange *sor;
- SelectionPtr destSIP;
- gxShape retShape, workShape;
- short count;
-
- if (layout == nil || selection == nil || (destSIP = *selection) == nil)
- {GXPostGraphicsError(parameter_is_nil); return nil;}
-
- HLock((Handle) selection);
- maxOffset = GXGetLayout(layout, nil, nil, nil, nil, nil, nil, nil, nil, nil);
-
- switch (destSIP->type)
- {
- case emptySelection:
- retShape = GXNewShape(gxEmptyType);
- break;
- case simpleCaret:
- off1 = destSIP->data.caret.offset - lineStart;
- if (off1 < 0) off1 = 0;
- else if (off1 > maxOffset) off1 = maxOffset;
- retShape = GXGetLayoutCaret(
- layout,
- (gxByteOffset) off1,
- highlightType,
- caretType,
- nil);
- break;
- case simpleRange:
- if (destSIP->data.range.ranges[0].minOffset == selectionExtremeEdge) off1 = 0;
- else
- {
- off1 = destSIP->data.range.ranges[0].minOffset - lineStart;
- if (off1 < 0) off1 = 0;
- else if (off1 > maxOffset) off1 = maxOffset;
- }
- if (destSIP->data.range.ranges[0].maxOffset == selectionExtremeEdge) off2 = maxOffset;
- else
- {
- off2 = destSIP->data.range.ranges[0].maxOffset - lineStart;
- if (off2 < 0) off2 = 0;
- else if (off2 > maxOffset) off2 = maxOffset;
- }
- retShape = GXGetLayoutHighlight(
- layout,
- (gxByteOffset) off1,
- (gxByteOffset) off2,
- highlightType,
- nil);
- break;
- case discontiguousRange:
- /* In this case, we need to build a multi-gxPolygon gxPolygons gxShape. */
- count = (short) destSIP->data.range.rangeCount;
- sor = &destSIP->data.range.ranges[0];
- retShape = GXNewShape(gxEmptyType);
- workShape = GXNewShape(gxEmptyType);
- while (count--)
- { /* gather loop */
- if (sor->minOffset == selectionExtremeEdge) off1 = 0;
- else
- {
- off1 = sor->minOffset - lineStart;
- if (off1 < 0) off1 = 0;
- else if (off1 > maxOffset) off1 = maxOffset;
- }
- if (sor->maxOffset == selectionExtremeEdge) off2 = maxOffset;
- else
- {
- off2 = sor->maxOffset - lineStart;
- if (off2 < 0) off2 = 0;
- else if (off2 > maxOffset) off2 = maxOffset;
- }
- GXGetLayoutHighlight(
- layout,
- (gxByteOffset) off1,
- (gxByteOffset) off2,
- highlightType,
- workShape);
- GXUnionShape(retShape, workShape);
- sor++;
- } /* end gather loop */
- GXDisposeShape(workShape);
- break;
- } /* end switch */
-
- HUnlock((Handle) selection);
- return retShape;
- } /* GetLayoutSelection */
-
- /* NewDiscontiguousSelection creates a discontiguous selection. It returns an empty
- selection if the argument is nil. */
-
- SelectionHandle NewDiscontiguousSelection(SelectionRanges *ranges)
- {
- long i;
- SelectionHandle returnedSelection, workingSelection;
- SelectionOffsetRange *thisSOR;
-
- returnedSelection = NewEmptySelection();
-
- if (ranges)
- {
- thisSOR = ranges->ranges;
- workingSelection = NewRangeSelection(thisSOR++);
-
- for (i = ranges->rangeCount - 1; i >= 0; --i)
- {
- UnionSelection(returnedSelection, workingSelection);
- SetRangeSelection(workingSelection, thisSOR++);
- }
-
- DisposeSelection(workingSelection);
- }
-
- return returnedSelection;
- } /* NewDiscontiguousSelection */
-